require 'active_record'
require 'logger'
require 'open-uri'
require 'sqlite3'
require 'slim'


ActiveRecord::Base.logger = Logger.new(STDERR) if STDERR.isatty
ActiveRecord::Base.establish_connection(
  adapter: 'sqlite3',
  database: 'db/main.sqlite3',
  pool: 5,
  timeout: 5000)
ActiveRecord::Migrator.migrate('db/migrate')


class Material < ActiveRecord::Base

  scope :menu, -> { where('content like ? or content like ?', '%今日菜单%', '%今天菜单%') }

  def menu_date
    /(?<m>\d+)月(?<d>\d+)日/ =~ content
    Date.civil(Time.now.year, m.to_i, d.to_i)
  end

  def menu_weekday
    content[/星期./].to_s.gsub('星期', '周')
  end

  # [1] pry(main)> Material.find(6857).menu_extract
  # => {"早餐"=>{""=>"咸鸭蛋、香菇肉包、蛋黄刀切、彩针蛋糕、萝卜丝煎饼、烤红薯、葱油拌面、虾皮"},
  #  "中餐"=>
  #   {""=>"酸菜鱼、干菜蒸仔排、腊味花菜、木耳包心菜、小米糖水、番茄蛋汤",
  #    "川湘菜"=>"雪菜小鸡腿、麻辣豆腐、木耳包心菜",
  #    "粤菜"=>"西芹炒鲜鱿鱼、土豆炖牛腩、韭黄炒肉丝、时蔬一道、玉米排骨汤",
  #    "盖浇饭"=>"红烧猪大排盖浇饭",
  #    "面档"=>"炸酱面、干菜仔排面",
  #    "卤水套餐"=>"卤水鹅肾、卤水贡丸、卤水鸡蛋、时蔬一道",
  #    "特价菜"=>"药材炖乳鸽5元/盅、蜜汁排骨10元/份、广东菜心炒"},
  #  "清蒸"=>{"、健康菜"=>""},
  #  "晚餐"=>
  #   {""=>"肉饼蒸蛋、香菇炖鸭、豇豆茄子、清炒青菜、绿豆糖水、山药排骨汤",
  #    "川湘菜"=>"一锅香、辣炒土豆、清炒青菜",
  #    "粤菜"=>"千叶豆腐、鱼香肉丝、蒸白枪鱼、时蔬一道、老鸡汤",
  #    "盖浇饭"=>"肉片小香芹盖浇饭",
  #    "面档"=>"牛肉面、香菇鸭块面",
  #    "特价菜"=>"药材炖乳鸽5元/盅、烧肉10元份、田园蔬3元/份",
  #    "水果"=>"梨"},
  #  "夜宵"=>{""=>"腊味炒米粉、猪肉水饺、皮蛋瘦肉粥、脆爽萝卜、黑米糕"}}
  def menu_extract
    result = {}
    content.lines do |l|
      key, value = l.chomp.gsub(/。$/, '').gsub(/^\s+/, '').split('：', 2)
      next unless key && value
      key = "中餐#{key}" if key.start_with?('卤水')
      key = key.gsub('（', '(').gsub('）', ')').gsub(/\([^\)]*\)/, '').gsub('窗口', '')
      (result[key[0, 2]] ||= {})[key[2..-1]] = value
    end
    result = menu_extract2 if result.empty?
    result
  end

  HEADERS = %w[早餐 中餐 晚餐 夜宵]

  def menu_extract2
    splitted = content.split(/[早中晚]餐|夜宵/)
    Hash[
      HEADERS.map.with_index do |header, i|
        [header, {'' => splitted[i + 1]}]
      end
    ]
  end


  def self.fetch!(id)
    url = "http://numenplus.yixin.im/singleNewsWap.do?materialId=#{id}&companyId=1"
    html = open(url).read.to_s
    body = html[/body>(.*)<\/body/m, 1]
    return if body.nil?

    body = body.gsub(/\s+/m, '').gsub('&nbsp;', ' ').gsub(/<[^>]*>/, "\n").gsub(/\n+/, "\n").gsub(/\A\s+|\s+\z/, '') if body
    return if body.empty? || body.include?('不存在')

    m = where(id: id).first_or_initialize
    m.content = body
    m.save!
  end

  def self.last_id
    x = last
    x ? x.id : 0
  end

  def self.fetch_next(lookahead = 150)
    # 150:
    # v=0;pluck(:ids).map do |x| r = x - v; v = x; r; end.max # => 137
    Material.transaction do
      id = last_id
      ttl = lookahead
      while ttl > 0
        id += 1
        ttl -= 1
        ttl = lookahead if fetch! id
      end
    end
  end

  def self.latest_menu
    # look ahead for at most (approx.) 2000 rows, it should be enough
    today = Time.now.to_date
    candadites = Material.where('id >= ?', last_id - 2000).menu.last(30).select do |r|
      # extract date and check
      (0..30).cover? r.menu_date - today rescue false
    end
    items = {}
    candadites.reverse.each do |c|
      items[c.menu_date] ||= c
    end
    items.values.sort_by(&:menu_date)
  end

end


def render_html
  @materials = Material.latest_menu
  @today = Time.now.to_date
  puts Slim::Template.new('menu.slim').render(self)
end

def fetch_materials
  Material.fetch_next
end


case ARGV.join[0]
when 'c'  # console
  require 'pry'
  binding.pry
when 'f'  # fetch
  fetch_materials
when 'r'  # render
  render_html
else
  puts "Usage #{$0} c | f | r"
end
